﻿using SDF.Core.Data;
using SDF.Core.Infrastructure;
using SDF.Plugin.Misc.SAPAdapter.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SDF.Core;
using SAP.Middleware.Connector;
using SDF.Plugin.Misc.SAPAdapter.Extensions;
using SDF.Services.Logging;
using SDF.Plugin.Misc.SAPAdapter.Models;
using Newtonsoft.Json.Linq;

namespace SDF.Plugin.Misc.SAPAdapter.Core
{
    public class SAPOperation : ISAPOperation
    {
        #region Fields
        // SAP连接对象
        private RfcDestination rfcDest;
        private readonly ILogger _log;
        #endregion

        #region Ctor
        public SAPOperation(string sapClientName)
        {
            this._log = EngineContext.Current.Resolve<ILogger>();
            var _sapClientRep = EngineContext.Current.Resolve<IRepository<SAPInstance>>();

            //获取SAP连接对象信息
            var _sapClient = _sapClientRep.TableNoTracking.FirstOrDefault(p => p.CodeName.Equals(sapClientName));
            (_sapClient == null).TrueThrow(string.Format("不存在{0}的SAP连接信息", sapClientName));
            _sapClient.Validate();

            //SAP连接对象
            rfcDest = _sapClient.ToRfcDestination();
        }
        #endregion

        #region Methods

        public bool Ping()
        {
            try
            {
                rfcDest.Ping();

                return true;
            }
            catch (Exception ex)
            {
                _log.Error($"SAP服务器[{rfcDest.Name}]连接失败", ex);
                return false;
            }

        }

        /// <summary>
        /// 获取SAP方法参数列表
        /// </summary>
        /// <param name="functionName"></param>
        /// <returns></returns>
        public IEnumerable<FunctionParamsModel> GetFunctionParams(string functionName)
        {
            functionName.NullOrEmptyCheck("functionName");

            IRfcFunction function = rfcDest.Repository.CreateFunction(functionName);
            var functionList = function.ToList();

            //只取输入、输出和表格类型参数
            //不能用functionList.Where()lambda表达式，因为小部分服务器不兼容
            List<IRfcParameter> functionFilter = new List<IRfcParameter>();
            for (int i = 0; i < functionList.Count; i++)
            {
                if (functionList[i].Metadata.Direction == RfcDirection.IMPORT ||
                    functionList[i].Metadata.Direction == RfcDirection.EXPORT ||
                    functionList[i].Metadata.Direction == RfcDirection.TABLES)
                {
                    functionFilter.Add(functionList[i]);
                }
            }

            var result = new List<FunctionParamsModel>();

            //格式转换
            functionFilter.OrderBy(p => p.Metadata.Direction).ToList().ForEach(p =>
            {
                result.Add(p.Metadata.ToFunctionParamsModel());
            });

            return result;
        }

        /// <summary>
        /// 获取SAP表结构
        /// </summary>
        /// <param name="tableName"></param>
        public IEnumerable<TableInfoModel> GetTableInfo(string tableName, string language = "1")
        {
            tableName.NullCheck("tableName");

            IRfcFunction function = rfcDest.Repository.CreateFunction("DDIF_FIELDINFO_GET");

            //输入参数
            function.SetValue("TABNAME", tableName);
            function.SetValue("LANGU", language);
            //执行
            function.Invoke(rfcDest);
            //返回结果
            IRfcTable rfc_result = function.GetTable("DFIES_TAB");

            //转换格式
            return rfc_result.ToTableInfoModel();
        }

        public IEnumerable<Dictionary<string, string>> GetTableData(string tableName, RfcReadTableParamsModel param)
        {
            tableName.IsNullOrEmpty().TrueThrow("表名不能为空");

            int rowSkip = 0;
            int rowCount = 0;
            string whereClause = string.Empty;
            List<string> fields = new List<string>();

            if (param != null)
            {
                rowSkip = param.RowSkip;
                rowCount = param.RowCount;
                whereClause = param.WhereClause;
                if (param.Fields != null)
                    fields = param.Fields.ToList();
            }

            try
            {
                //引用SAP方法
                IRfcFunction function = rfcDest.Repository.CreateFunction("RFC_READ_TABLE");

                //输入参数
                #region
                function.SetValue("QUERY_TABLE", tableName);
                function.SetValue("ROWSKIPS", rowSkip);
                function.SetValue("ROWCOUNT", rowCount);

                //where条件
                if (whereClause.IsNullOrEmpty() == false)
                {
                    IRfcTable optionsTable = function.GetTable("OPTIONS");

                    List<string> wheres = this.convertToSAPWhereString(whereClause);
                    foreach (string w in wheres)
                    {
                        optionsTable.Append();
                        optionsTable.CurrentRow.SetValue("TEXT", w);
                    }
                }

                //待获取的列名
                IRfcTable fieldsTable = function.GetTable("FIELDS");
                if (fields != null && fields.Any())
                {
                    //如果指定待获取列名，直接使用
                    fields.Reverse();
                    fields.ToList().ForEach(f =>
                    {
                        fieldsTable.Insert();
                        fieldsTable.CurrentRow.SetValue("FIELDNAME", f.ToString());
                    });
                }
                else
                {
                    //如果没有指定字段，则不赋值。NCO会取出所有字段
                }
                #endregion

                //执行
                function.Invoke(rfcDest);

                //返回值
                IRfcTable rfcData = function.GetTable("DATA");
                //FIELDS返回值为解析DATA返回用
                IRfcTable rfcFields = function.GetTable("FIELDS");

                //RFCTable转换DataTable
                var data = formatRfcReadTableResult(rfcData, rfcFields);

                return data;
            }
            catch (Exception ex)
            {
                throw new Exception("读取SAP表数据异常", ex);
            }
        }

        /// <summary>
        /// 执行SAP方法，支持SAP的IMPORT、EXPORT、TABLES三种类型，不支持CHANGING类型。
        /// 考虑页面处理的简便要求，全部输入输出参数不支持多级嵌套，即表格里套表格。
        /// </summary>
        /// <param name="functionName"></param>
        /// <param name="funcParams"></param>
        public JObject ExecuteSAPFunction(string functionName, JObject funcParams)
        {
            (functionName.IsNullOrEmpty()).TrueThrow("SAP方法名不能为空");
            (funcParams == null).TrueThrow("SAP方法所需要参数不能为空");

            try
            {
                //创建方法
                IRfcFunction function = rfcDest.Repository.CreateFunction(functionName);

                //输入参数(IMPORT和TABLE)
                function.ToList().Where(p =>
                    p.Metadata.Direction == RfcDirection.IMPORT ||
                    p.Metadata.Direction == RfcDirection.TABLES
                ).ToList().ForEach(p => this.setImportParams(p.Metadata, p, funcParams));

                //执行
                function.Invoke(rfcDest);

                //输出参数(EXPORT和TABLE)
                function.ToList().Where(p =>
                    p.Metadata.Direction == RfcDirection.EXPORT ||
                    p.Metadata.Direction == RfcDirection.TABLES
                ).ToList().ForEach(p => this.getExportParams(p.Metadata, p, funcParams));

                return funcParams;
            }
            catch (Exception ex)
            {
                throw new Exception("执行RFC异常", ex);
            }

        }
        #endregion

        #region PrivateMethods

        /// <summary>
        /// 拼接sap所需要的条件格式
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        private List<string> convertToSAPWhereString(string where)
        {
            List<string> result = new List<string>();
            int whereLength = where.Length;

            int index = 0;
            while (true)
            {
                int length = 72;
                int spaceindex = 0;
                if (index >= whereLength)
                {
                    break;
                }
                if (whereLength > 72)
                {
                    if (index + length > whereLength)
                    {
                        length = whereLength - index;
                    }
                    spaceindex = where.Substring(index, length).LastIndexOf(' ');
                }
                else
                {
                    length = whereLength;
                    spaceindex = whereLength;
                }
                if (spaceindex == -1)
                {
                    spaceindex = length;
                }
                result.Add(where.Substring(index, spaceindex));
                index += spaceindex + 1;
            }
            return result;
        }

        /// <summary>
        /// 格式化RFC_READ_TABLE返回结果
        /// RFC_READ_TABLE返回的Table比较特殊，所有字段都放在一个名为WA的列里。
        /// 需要按OFFSET和LENGTH截取结果
        /// </summary>
        /// <param name="data">待转换的IRfcTable</param>
        /// <param name="fields">IRfcTable的列集合</param>
        /// <returns></returns>
        private IEnumerable<Dictionary<string, string>> formatRfcReadTableResult(IRfcTable data, IRfcTable fields)
        {
            (fields == null || !fields.Any()).TrueThrow("SAP数据字段不能为空");
            (data == null).TrueThrow("待转换的RFCTable不能为空");

            var result = new List<Dictionary<string, string>>();

            try
            {
                foreach (IRfcStructure row in data)
                {
                    #region 
                    Dictionary<string, string> dicData = new Dictionary<string, string>();

                    string rowData = row.GetString("WA");

                    int length = 0;
                    fields.ToList().ForEach(f =>
                    {
                        string key = f.GetString("FIELDNAME").Trim();
                        string value = string.Empty;

                        if (rowData.Length - length > 0)
                        {
                            if (rowData.Length - length < f.GetInt("LENGTH"))
                                value = rowData.Substring(f.GetInt("OFFSET"), rowData.Length - length).TrimEnd();
                            else
                                value = rowData.Substring(f.GetInt("OFFSET"), f.GetInt("LENGTH")).TrimEnd();
                        }

                        dicData.Add(key, value);

                        length += f.GetInt("LENGTH");
                    });

                    result.Add(dicData);
                    #endregion
                }
            }
            catch (Exception ex)
            {
                throw new Exception("RFCTable转换为DataTable异常", ex);
            }

            return result;
        }

        /// <summary>
        /// 为输入参数赋值
        /// </summary>
        /// <param name="rfcParameter">单个待输入值参数</param>
        /// <param name="values">值的集合</param>
        private void setImportParams(RfcElementMetadata metaData, IRfcElement rfcParameter, JToken values)
        {
            var value = values[metaData.Name];

            if (value != null)
            {
                switch (metaData.DataType)
                {
                    case RfcDataType.TABLE:
                        setSAPTableValue(metaData, rfcParameter, value);
                        break;
                    case RfcDataType.STRUCTURE:
                        setSAPStructureValue(metaData, rfcParameter, value);
                        break;
                    default:
                        rfcParameter.SetValue(value.Value<string>());
                        break;
                }
            }
        }

        private void setSAPTableValue(RfcElementMetadata metaData, IRfcElement rfcParameter, JToken value)
        {
            if (value == null || value.HasValues == false)
                return;

            IRfcTable table = rfcParameter.GetTable();
            table.Clear();

            //这需要改进，不能以值赋TABLE,应该以TABLE找值
            value.ToList().ForEach(row =>
            {
                table.Insert();

                var currentRow = table.CurrentRow;

                currentRow.ToList().ForEach(s =>
                {
                    setImportParams(s.Metadata, s, row);
                });
            });

            rfcParameter.SetValue(table);
        }

        /// <summary>
        /// 为Struct类型参数赋值
        /// </summary>
        /// <param name="metaData">参数元数据</param>
        /// <param name="rfcParameter">参数本身</param>
        /// <param name="value">参数值</param>
        private void setSAPStructureValue(RfcElementMetadata metaData, IRfcElement rfcParameter, JToken value)
        {
            if (value == null || value.HasValues == false)
                return;

            IRfcStructure structure = rfcParameter.GetStructure();
            structure.ToList().ForEach(s =>
            {
                JToken itemValue = value[metaData.Name];
                setImportParams(metaData, s, itemValue);
            });

            rfcParameter.SetValue(structure);
        }

        private void getExportParams(RfcElementMetadata metaData, IRfcElement rfcParameter, JToken valuesToBeSet)
        {
            if (valuesToBeSet[metaData.Name] == null)
                valuesToBeSet[metaData.Name] = "";

            switch (metaData.DataType)
            {
                case RfcDataType.TABLE:
                    valuesToBeSet[metaData.Name] = getSAPTableValue(metaData, rfcParameter);
                    break;
                case RfcDataType.STRUCTURE:
                    getSAPStructureValue(metaData, rfcParameter, valuesToBeSet[metaData.Name]);
                    break;
                default:
                    valuesToBeSet[metaData.Name] = rfcParameter.GetString();
                    break;
            }
        }

        private JToken getSAPTableValue(RfcElementMetadata metaData, IRfcElement rfcParameter)
        {
            IRfcTable rfcTable = rfcParameter.GetTable();

            JArray rows = new JArray();

            //循环行
            rfcTable.ToList().ForEach(dataRow =>
            {
                JObject newRow = new JObject();

                //循环列
                dataRow.ToList().ForEach(col =>
                {
                    getExportParams(col.Metadata, col, newRow);
                });

                rows.Add(newRow);
            });

            return rows;
        }

        private void getSAPStructureValue(RfcElementMetadata metaData, IRfcElement rfcParameter, JToken valuesToBeSet)
        {

        }
        #endregion
    }
}